package com.topscomm.meet.service.impl;

import com.topscomm.base.BaseRemindTemplate;
import com.topscomm.base.BaseSystemConst;
import com.topscomm.base.service.IBaseRemindTaskService;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.meet.MeetSystemConst;
import com.topscomm.meet.dao.IMeetPersonRecordDao;
import com.topscomm.meet.dto.ConfirmInfo;
import com.topscomm.meet.pojo.MeetManageEntity;
import com.topscomm.meet.pojo.MeetPersonRecordEntity;
import com.topscomm.meet.service.IMeetJoinConfirmService;
import com.topscomm.meet.service.IMeetManageService;
import com.topscomm.meet.service.IMeetPersonRecordService;
import com.topscomm.meet.service.impl.auto.MeetPersonRecordServiceAuto;
import com.topscomm.pub.util.ConvertUtil;
import com.topscomm.pub.util.StringBufferProxy;
import com.topscomm.tap.common.DatacodeCache;
import com.topscomm.work.service.impl.WorkScheduleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import static com.topscomm.meet.MeetSystemConst.MeetSubmitStateEnum.*;

@Slf4j
@Service(value = "MeetJoinConfirmService")
@Scope(value = "singleton")
public class MeetJoinConfirmServiceImpl extends MeetPersonRecordServiceAuto implements IMeetJoinConfirmService {
    @Autowired
    IMeetPersonRecordDao dao;
    @Autowired
    IMeetPersonRecordService meetPersonRecordService;
    @Autowired
    DatacodeCache datacodeCache;
    @Autowired
    IMeetManageService meetManageService;
    @Autowired
    IBaseRemindTaskService baseRemindTaskService;

    public static class ConfirmBool {
        public static final Boolean confirm = true;
        public static final Boolean refuse = false;
    }

    /**
     * 根据来源及来源id 及确认状态 进行参会确认或反馈 人员状态更新
     *
     * @param
     * @return
     * @throws
     * @author xinfushuo
     * @date 2023/3/17
     * @modify
     */
    @Transactional(rollbackFor = Exception.class)
    public void joinUpdate(MeetPersonRecordEntity personRecord, Boolean confirm, String reason, String desc) {
        personRecord.setSubmitdate(new Date());
        //判断是否参会 是为 1 否为2
        personRecord.setSubmitstate(ConfirmBool.confirm.equals(confirm) ?
                AttendSubmit : MeetSystemConst.MeetSubmitStateEnum.NoAttendSubmit);
        //确认参会情况填写内容
        if (!confirm) {
            personRecord.setSubmitdesc(desc);
            personRecord.setSubmittype(reason);
        } else {
            personRecord.setSubmitdesc("");
            personRecord.setSubmittype("");
        }
        this.updateFields(personRecord, new ArrayList<>(Arrays.asList(MeetPersonRecordEntity.FieldSubmitstate,
                MeetPersonRecordEntity.FieldSubmitdate,
                MeetPersonRecordEntity.FieldSubmittype,
                MeetPersonRecordEntity.FieldSubmitdesc)));
    }

    /**
     * 参会反馈的方法
     *
     * @throws
     * @author xinfushuo
     * @parama
     * @date 2023/3/17
     * @modify
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void joinConfirm(ConfirmInfo confirmInfo) {
        String res = "";
        //当前人需与反馈人一致
        if (!this.getSessionUserBean().getUser().getCode().contentEquals(confirmInfo.getUserCode())) {
            throw new ServiceException("无法为他人进行参会操作。");
        }
        //根据sourceid sourcetype usercode 找到对应人员记录
        List<Map<String, Object>> recordMap = this.queryMap(convertToMap(confirmInfo), "queryPersonForConfirm");
        if (recordMap == null || recordMap.isEmpty()) {
            throw new ServiceException("未查询到相关会议，请确认相关会议是否已撤销");
        }
        MeetPersonRecordEntity entity = new MeetPersonRecordEntity();
        entity.convertFromMap(recordMap.get(0));
        //查询旧的参会反馈信息
        ConfirmInfo oldConfirmInfo = loadJoinInfo(ConfirmInfo.builder().sourceId(confirmInfo.getSourceId()).sourceType(confirmInfo.getSourceType()).userCode(confirmInfo.getUserCode()).build());
        //查询会议信息
        MeetManageEntity meetEntity = meetManageService.queryById(entity.getMeetid());
        //检测是否重复参会 或者时间已过无需参会
        if (AttendSubmit == entity.getSubmitstate() && ConfirmBool.confirm.equals(confirmInfo.getConfirmState())) {
            throw new ServiceException("您已参会,无需再次参会。");
        }
        if (NoAttendSubmit == entity.getSubmitstate() && ConfirmBool.confirm.equals(confirmInfo.getConfirmState())) {
            //拒绝参会改为确认后，清空原有指派人员
            this.meetPersonRecordService.deleteByAssignUser(String.valueOf(meetEntity.getId()), this.getSessionUserBean(), "", "");
            //发送参会反馈 人员已参会消息
            String dept = datacodeCache.getValueDynamic("CboDept", getFristDeptCode(entity.getDeptcode()), "code", "name");
            String messagetemp = new StringBufferProxy().appendLineSingle(BaseRemindTemplate.JoinConfirmRemindTemplate.feedbackJoinContent, dept, entity.getUsername(), entity.getUsercode(), WorkScheduleService.getDateStringWithWeek(meetEntity.getBegintime()), meetEntity.getName()).toString();
            this.baseRemindTaskService.insert(this.createRemindTaskEntity(BaseSystemConst.BaseActionType.Remind, entity.getMeetid(), "MeetJoinFeedBack", BaseRemindTemplate.JoinConfirmRemindTemplate.feedbacktitle, messagetemp, new Date(), meetEntity.getUsercode(), meetEntity.getUsername()));
        }
        if (new Date().after(ConvertUtil.convertToDate(entity.getValue("meetendtime")))) {
            throw new ServiceException("会议已结束，无需进行参会");
        }

        //拒绝参会后 发送消息
        if (ConfirmBool.refuse.equals(confirmInfo.getConfirmState())) {
            String dept = datacodeCache.getValueDynamic("CboDept", getFristDeptCode(entity.getDeptcode()), "code", "name");
            String resonDisp = new StringBufferProxy().appendSingle(datacodeCache.getValueDynamic("JoinRefuseReason", confirmInfo.getReason(), "code", "name")).append("。").append(ConvertUtil.convertToString(confirmInfo.getDescription())).toString();
            StringBufferProxy assignText = new StringBufferProxy();
            handleAssignUser(confirmInfo.getAssignUsers(), (code) -> assignText.appendSingle("指派参会人员：").toString(), ((code, name) -> assignText.appendSingle(name).append("[").append(code).append("]").toString()));
            String messagetemp = new StringBufferProxy().appendLineSingle(BaseRemindTemplate.JoinConfirmRemindTemplate.feedbackRefuseContent, dept, entity.getUsername(), entity.getUsercode(), WorkScheduleService.getDateStringWithWeek(meetEntity.getBegintime()), meetEntity.getName(), resonDisp, assignText.toString()).toString();
            //仅当内容变更时,或状态变更时发送反馈消息
            if (!entity.getSubmittype().contentEquals(confirmInfo.getReason())
                    || !ConvertUtil.convertToString(entity.getSubmitdesc()).contentEquals(ConvertUtil.convertToString(confirmInfo.getDescription()))
                    || AttendSubmit == entity.getSubmitstate()
            ) {
                this.baseRemindTaskService.insert(this.createRemindTaskEntity(BaseSystemConst.BaseActionType.Remind, entity.getMeetid(), "MeetJoinFeedBack", BaseRemindTemplate.JoinConfirmRemindTemplate.feedbacktitle, messagetemp, new Date(), meetEntity.getUsercode(), meetEntity.getUsername()));
            }
            //检测指派人重复
                if(ConfirmBool.refuse.equals(confirmInfo.getConfirmState()) && confirmInfo.getAssignUsers()!=null && !confirmInfo.getAssignUsers().isEmpty()){
                    List<String> userRecordField = new ArrayList<>(Arrays.asList(MeetPersonRecordEntity.FieldUsercode,MeetPersonRecordEntity.FieldUsername)) ;
                    List<String> assignuserList = new ArrayList<>(Arrays.asList(confirmInfo.getAssignUsers().split(",")));
                    //检测重复人员并提示
                    List<Map<String,Object>> userList = this.meetPersonRecordService.queryMapFieldsByWhere("meetid = "+meetEntity.getId(),userRecordField);
                    StringBufferProxy dispUser = new StringBufferProxy();
                    userList.stream().filter(u-> assignuserList.contains(ConvertUtil.convertToString(u.get("usercode")))).forEach(u->{
                        dispUser.appendSingle("{0}[{1}]",ConvertUtil.convertToString(u.get("usercode")),ConvertUtil.convertToString(u.get("username")));
                    });
                    if(!dispUser.toString().isEmpty()){
                        throw new ServiceException("您指派的人员："+dispUser+"已参会，请重新选择");
                    }
                }
            // 指派人员产生不一致时 或者原因变化时 将原指派人员人员从会议中删除
            if (!MeetSystemConst.MeetJoinRefuseReason.Assign.contentEquals(ConvertUtil.convertToString(confirmInfo.getReason())) || !ConvertUtil.convertToString(confirmInfo.getAssignUsers()).contentEquals(ConvertUtil.convertToString(oldConfirmInfo.getAssignUsers()))) {
                this.meetPersonRecordService.deleteByAssignUser(String.valueOf(meetEntity.getId()), this.getSessionUserBean(), "", "");
            }
            //仅当原因为4 处理指派
            if (MeetSystemConst.MeetJoinRefuseReason.Assign.contentEquals(ConvertUtil.convertToString(confirmInfo.getReason()))) {
                //处理指派参会
                handleAssignUser(confirmInfo.getAssignUsers(), (code) -> null, ((code, name) -> meetPersonRecordService.assign(entity.getMeetid(), code, name)));
            }
        }
        //更新状态
        joinUpdate(entity, confirmInfo.getConfirmState(), confirmInfo.getReason(), confirmInfo.getDescription());

    }

    /**
     * 指派人员处理方法
     *
     * @param 指派人员及两个钩子函数
     * @author xinfushuo
     * @date 2023/3/21
     */
    private void handleAssignUser(String assignUsers, UnaryOperator<String> prehandle, BiFunction<String, String, String> handleFunciton) {
        if (assignUsers != null && !assignUsers.isEmpty()) {
            prehandle.apply(assignUsers);
            List<String> userCodes = Arrays.stream(assignUsers.split(",")).collect(Collectors.toList());
            userCodes.forEach(code -> {
                String name = this.datacodeCache.getValueDynamic("CboUser", code, "code", "name");
                handleFunciton.apply(code, name);
            });
        }
    }

    /**
     * 根据参会人员、sourcetype sourceid 获取展示信息
     *
     * @param ConfirmInfo
     * @return ConfirmInfo
     * @author xinfushuo
     * @date 2023/3/20
     * @modify
     */
    @Override
    public ConfirmInfo loadJoinInfo(ConfirmInfo confirmInfo) {
        ConfirmInfo info = (ConfirmInfo) this.dao.queryEntityByMap(this.convertToMap(confirmInfo), "loadConfimInfo");
        if (info == null) {
            //返回不显示的信息
            return ConfirmInfo.builder().showConfirm(false).userCode(confirmInfo.getUserCode()).build();
        }
        MeetManageEntity meetManageEntity = (MeetManageEntity) this.dao.queryEntityByMap(this.convertToMap(confirmInfo), "queryMeetBySourceType");
        //会议创建人 会议管理人 会议时间已过 无需展示
        String meetmanager = ConvertUtil.convertToString(meetManageEntity.getManageusercodes());
        boolean isManager = !meetmanager.isEmpty() && Arrays.stream(meetmanager.split(",")).anyMatch(code -> confirmInfo.getUserCode().contentEquals(code));
        Boolean showConfirm = !(confirmInfo.getUserCode().contentEquals(ConvertUtil.convertToString(meetManageEntity.getUsercode()))
                || isManager
                || new Date().after(meetManageEntity.getEndtime()));
        confirmInfo.setShowConfirm(showConfirm);
        confirmInfo.setConfirmState(info.getConfirmState());
        confirmInfo.setDescription(info.getDescription());
        confirmInfo.setAssignUsers(info.getAssignUsers());
        //处理参会人展示
        if (info.getAssignUsers() != null && !info.getAssignUsers().isEmpty()) {
            List<String> codes = new ArrayList<>(Arrays.asList(info.getAssignUsers().split(",")));
            String nametemp = codes.stream().map(code -> datacodeCache.getValueDynamic("CboUser", code, "code", "name")).collect(Collectors.joining(","));
            confirmInfo.setAssignUsernames(nametemp);
        }
        confirmInfo.setReason(info.getReason());
        return confirmInfo;
    }

    /**
     * @param mapRow
     * @author: donghang
     * @date: 2020-10-31
     * @description:设置字段显示值
     * @modify:
     */
    @Override
    public void setDispFields(Map<String, Object> mapRow, DatacodeCache datacodeCache) {
        String temp;
        if (mapRow.get("reason") != null) {
            temp = mapRow.get("reason").toString();
            mapRow.put("dispreason", datacodeCache.getValueDynamic("JoinRefuseReason", temp, "code", "name"));
        }
        if (mapRow.get("confirmstate") != null) {
            temp = mapRow.get("confirmstate").toString();
            mapRow.put("dispconfirmstate", datacodeCache.getValueDynamic("MeetSubmitState", temp, "code", "name"));
        }
        if (mapRow.get("deptcode") != null) {
            temp = mapRow.get("deptcode").toString();
            mapRow.put("dispdeptcode", datacodeCache.getValueDynamic("CboDeptFull", temp, "code", "name"));
        }
        if (mapRow.get("assignUsers") != null) {
            temp = mapRow.get("assignUsers").toString();
            List<String> codes = new ArrayList<>(Arrays.asList(temp.split(",")));
            String disptemp = codes.stream().map(code -> {
                String name = datacodeCache.getValueDynamic("CboUser", code, "code", "name");
                return new StringBufferProxy().appendSingle("{0}[{1}]", name, code).toString();
            }).collect(Collectors.joining(","));
            mapRow.put("dispassignUsers", disptemp);
        }
    }
}
